package com.baba.vote.util;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;

/**
 * @author moxinHuoHuo
 * @create 2019/10/24 上午10:52
 */
@Slf4j
public class JsonUtil {

  private static ObjectMapper objectMapper = new ObjectMapper();

  // 初始化objectMapper对象
  static {
    // 对象的所有字段全部列入
    // 可选的属性有ALWAYS，NON_NULL(不为NULL的属性进行序列化)，NON_DEAFAULT(不为默认属性的进行序列化)，NON_EMPTY(不为空的进行序列化)
    objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);

    // 取消默认转换timestamps形式
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

    // 忽略空Bean转json的错误（空Bean就是没有get和set方法）
    objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

    // 所有的日期格式都统一为以下的样式，即yyyy-MM-dd HH:mm:ss
    objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

    // 忽略在json字符串中存在，但是在java对象中不存在对应属性的情况。防止错误
    // 当调用外部的接口的时候，如果外部的接口发生改动，则返回的Json发生改动，可能增加或减少字段。如果不设置此选项为false，Json的字段与Bean中的字段不匹配，则会进行报错。
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  }

  // 对象转String
  public static <T> String obj2String(T obj) {
    if (obj == null) {
      return null;
    }
    try {
      return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);
    } catch (Exception e) {
      log.warn("object转换成String错误！", e);
      return null;
    }
  }

  // 对象转String(格式化)
  public static <T> String obj2StringPretty(T obj) {
    if (obj == null) {
      return null;
    }
    try {
      return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
    } catch (Exception e) {
      log.warn("object转换成String错误！", e);
      return null;
    }
  }

  // String转对象
  public static <T> T string2Obj(String str, Class<T> clazz) {
    if (StrUtil.isEmpty(str) || clazz == null) {
      return null;
    }

    try {
      // 判断对象是否String类型，是则直接返回，否则转成clazz对象
      return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
    } catch (Exception e) {
      log.warn("String转换成Object错误！", e);
      return null;
    }
  }

  /*Json数组转集合对象
   * 例如：List<User>
   * typeReference参数 传需要转换成的集合对象，例：List<User>
   */
  public static <T> T string2Obj(String str, TypeReference<T> typeReference) {
    if (StrUtil.isEmpty(str) || typeReference == null) {
      return null;
    }

    try {
      return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));
    } catch (Exception e) {
      log.warn("String转换成Object错误！", e);
      return null;
    }
  }

  /* 功能同上
   * collectionClass参数 传递集合，例：List，Map
   * elementClasses参数 传递集合所包含的泛型，可传递多个类字节码对象
   */
  public static <T> T string2Obj(String str, Class<?> collectionClass, Class<?>... elementClasses) {
    JavaType javaType = objectMapper.getTypeFactory().constructParametricType(collectionClass, elementClasses);

    try {
      return objectMapper.readValue(str, javaType);
    } catch (Exception e) {
      log.warn("String转换成Object错误！", e);
      return null;
    }
  }

  // -------------------test-----------------
  public static void main(String[] args) {


  }

}

